import axios, { type AxiosInstance, type AxiosResponse, HttpStatusCode } from 'axios'
import Cookies from 'js-cookie'
import qs from 'qs'
// 引入全局加载遮罩层
import Spin from '@/components/Loading'

// Create a new Axios instance
const api: AxiosInstance = axios.create({
  baseURL: '',
  timeout: 50000, // 全局超时时间
  paramsSerializer: {
    serialize: (params: any) => {
      return qs.stringify(params, { arrayFormat: 'repeat' })
    },
  },
})

// 重新登录函数
const reLogin = () => {
  // 如果已经在登录页，不再跳转
  // 需要使用正则匹配
  if (window.location.pathname.match(/^\/mobile\/login.*/))
    return Promise.reject(new Error('Need to login again'))

  window.location.href = '/mobile/login'
  // 清除浏览器全部临时缓存
  Cookies.remove('access_token_lf')
  Cookies.remove('refresh_token_lf')
  return Promise.reject(new Error('Need to login again'))
}

/*
  * Axios请求拦截器，对请求进行处理
  */
api.interceptors.request.use(
  (config) => {
    const controller = new AbortController()

    // 检查路径是否为公共路径，不需要 Token
    const publicPaths = ['/java/user/publicKey', '/java/user/login', '/java/user/school_login', '/java/user/school_cas_login', '/java/user/register', '/java/user/personal_register']
    const isPublicPath = publicPaths.some(path => config.url?.includes(path))

    if (!isPublicPath) {
      const accessToken = Cookies.get('access_token_lf')

      if (!accessToken)

        return reLogin() // 如果没有 Token 并且需要，跳转到登录页面

      // 如果 Token 存在，添加到 Authorization 头
      config.headers.Authorization = `Bearer ${accessToken}`
    }

    Spin.show('加载中...')
    return {
      ...config,
      signal: controller.signal,
    }
  },
  (error) => {
    return Promise.reject(error)
  },
)

/**
 * 正常返回时的响应拦截器处理函数
 * @param response 响应结果
 * @returns 如果响应成功，则返回响应的data属性；否则，抛出错误或者执行其他操作
 */
const handleResponse = (response: AxiosResponse<any>) => {
  Spin.hide()
  // note: 具体错误判断
  // 判断是否是401，401也需要重新登录
  const status = Number(response.data.code)
  const status2 = Number(response.status)
  // 如果status为null,那么查看response.status字段
  // 如果都是null,那么抛出异常
  if (Number.isNaN(status) && Number.isNaN(status2))
    throw response.data

  // 如果status为null,那么查看status2字段，否则还是查看status字段
  if (Number.isNaN(status) && status2 >= HttpStatusCode.Ok && status2 < 300) {
    // 也是返回正常的
    return response.data
  }

  if (status === HttpStatusCode.Unauthorized) {
    // 重新登录
    return reLogin()
  }
  // 正常请求
  if (status >= HttpStatusCode.Ok && status < 300)
    return response.data

  // 处理普遍其他异常
  if (status !== HttpStatusCode.Ok && status !== 1)
    throw response.data

  return response.data
}

/*
  * Axios响应拦截器，对响应进行处理
  */
api.interceptors.response.use(
  handleResponse, (error) => {
    Spin.hide()
    // note: 处理网络请求失败的情况，一般不需要处理
    const status = Number(error.response?.status)

    // 检测status 是否是NaN
    if (Number.isNaN(status))
      return Promise.reject(error)

    // 如果status也是20x，说明是正常的返回
    if (status >= HttpStatusCode.Ok && status < 300)
      return Promise.resolve(error.response.data)
    if (status === HttpStatusCode.Unauthorized) {
      // 重新登录
      return reLogin()
    }

    return Promise.reject(error.response.data)
  },
)

export { api }
